home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / machserver / 1.098 / timer / timerClock.c < prev    next >
C/C++ Source or Header  |  1990-10-13  |  15KB  |  449 lines

  1. /*
  2.  * timerClock.c --
  3.  *
  4.  *    Kernel utility procedures to manipulate clocks values.
  5.  *
  6.  *  The routines in this module provide the interface between routines in 
  7.  *  the human oriented time and the machine dependent representation of 
  8.  *  time, the Timer_Ticks format. The Timer_Ticks format is used
  9.  *  for a specific purpose: to make the operations associated with the
  10.  *  callback timer and timer queue run fast. These operations include
  11.  *  starting the timer, scheduling a routine and calling a routine at its
  12.  *  scheduled time.  Unlike the Time format, which represents time in
  13.  *  seconds and microseconds, the Timer_Ticks format represents time in a
  14.  *  machine-dependent way. Timer_Ticks are defined in timerTicks.h in the 
  15.  *  machine-dependent directorys. Example Timer_Ticks format are as follows:
  16.  *  Sun-2: Timer_Ticks is a value based on the hardware's free-running 
  17.  *  counter and the number of times it has wrapped around. 
  18.  *  Sun-3: the hardware free-running counter format is easily converted
  19.  *  to the Time format, so no distinction is made between Time and Timer_Ticks.
  20.  *
  21.  *  A time value in the Timer_Ticks format is a hardware-dependent 64-bit
  22.  *  number that represents a specific or absolute point in time since some
  23.  *  some event (on the Sun-2, since the system was booted).  A time value
  24.  *  that is relative to an absolute time is called an interval.  By
  25.  *  definition, an interval is a hardware-dependent unsigned 32-bit number.  
  26.  *  The operations * and / can be used on intervals since they are integers.
  27.  *
  28.  *  There are several constraints imposed on the Timer_Ticks format to
  29.  *  decrease complexity and overhead in using the format.  First, it can
  30.  *  not be used to represent negative time values.  Second, the routines
  31.  *  are not general. For example, there are no multiply and divide
  32.  *  routines for Timer_Ticks values.  Full generality is obtained by using
  33.  *  the Time module.
  34.  *
  35.  * Copyright 1985, 1988 Regents of the University of California
  36.  * Permission to use, copy, modify, and distribute this
  37.  * software and its documentation for any purpose and without
  38.  * fee is hereby granted, provided that the above copyright
  39.  * notice appear in all copies.  The University of California
  40.  * makes no representations about the suitability of this
  41.  * software for any purpose.  It is provided "as is" without
  42.  * express or implied warranty.
  43.  *
  44.  */
  45.  
  46. #ifndef lint
  47. static char rcsid[] = "$Header: /sprite/src/kernel/timer/RCS/timerClock.c,v 9.5 90/10/13 17:05:11 mendel Exp $ SPRITE (Berkeley)";
  48. #endif not lint
  49.  
  50. #include "sprite.h"
  51. #include "proc.h"
  52. #include "sync.h"
  53. #include "timer.h"
  54. #include "timerInt.h"
  55. #include "spriteTime.h"
  56. #include "timerTick.h"
  57. #include "machMon.h"
  58.  
  59. /*
  60.  *  Universal Time is the number of seconds since 1/1/1970, Greenwich Time.
  61.  *  The time of day is kept in Universal Time. We use the terms "time of
  62.  *  day" and "universal time" interchangably, although the latter is
  63.  *  probably more descriptive. Universal time is mainly used by user-level
  64.  *  programs. "System time" is what the kernel typically uses to measure
  65.  *  time.  System time is the amount of time that the machine has been up.
  66.  *  It is usually maintained by a free-running counter and expressed in
  67.  *  units of ticks. System time is a more useful abstraction since it
  68.  *  is not reset, whereas universal time can be adjusted by a system call.
  69.  *
  70.  *  The term "time" is very overloaded in both the comments and the code.
  71.  *  I've tried to make it as clear as possible which format a particular
  72.  *  time variable is stored in.  Time variables with standard names are
  73.  *  of type "Time".  Time variables with "Tk" appended to their names
  74.  *  are of type "Timer_Ticks".  There may be exceptions to this naming
  75.  *  scheme.
  76.  *
  77.  *  Universal time can be obtained through one of two routines.
  78.  *  Timer_GetRealTimeOfDay is quite accurate but the routine is slow due
  79.  *  to the conversion from internal Timer_Ticks format to Time format.
  80.  *  The other value is timerTimeOfDay and is returned by
  81.  *  Timer_GetTimeOfDay.  The value is updated at every request timer
  82.  *  interrupt by adding the amount of time between interrupts and hence is
  83.  *  very inexpensive to calculate.  Also, the resolution is limited to the
  84.  *  time between interrupts. However, the value is not always accurate
  85.  *  because a timer interrupt can be delayed, therefore it is a close
  86.  *  approximation to the real time of day.  To keep the value roughly
  87.  *  accurate, every 10 seconds timer_UniversalApprox is updated to the real
  88.  *  time of day by a routine called from the timer queue.  The value
  89.  *  of timer_UniversalApprox is guaranteed to be monotonically increasing
  90.  *  between calls to Timer_SetTimeOfDay.
  91.  *
  92.  *  When the universal time is initially set with Timer_SetTimeOfDay, the
  93.  *  current system time is recorded (in systemWhenUniversalSetTk) along with 
  94.  *  the new value for the universal time (in universalWhenSetTk).
  95.  *  This value for universal time is not incremented. When 
  96.  *  Timer_GetTimeOfDay is called, the current universal time is calculated by 
  97.  *  reading the current system time and subtracting from it the system time 
  98.  *  when Timer_SetTimeOfDay was called. This difference is added to the 
  99.  *  recorded universal time to give the current universal time.
  100.  *  
  101.  *  timerUniversalToLocalOffset is used to convert from universal time
  102.  *  to local time. It is the number of minutes to add to universal time
  103.  *  to compute the local time. For example, timerLocalOffset for the 
  104.  *  Pacific time zone is -540 minutes. The local time of day is computed 
  105.  *  by multiplying timerUniversalToLocalOffset by 60 and adding the result 
  106.  *  to the universal time.
  107.  *
  108.  *  timerDSTAllowed is a flag to indicate if Daylight Savings Time is allowed.
  109.  *  A few states, such as Arizona, do not have DST.
  110.  *  (TRUE == DST is allowed, FALSE == DST is not allowed).
  111.  */
  112.  
  113. static Timer_Ticks systemWhenUniversalSetTk;
  114. static Timer_Ticks universalWhenSetTk;
  115.  
  116. Time           timer_UniversalApprox;
  117. int         timerUniversalToLocalOffset;
  118. Boolean     timerDSTAllowed;
  119.  
  120. /*
  121.  * Semaphore protecting the above time of day variables.
  122.  */
  123.  
  124. Sync_Semaphore    timer_ClockMutex;
  125.  
  126.  
  127. /*
  128.  * UpdateTimeOfDay() adjusts timerTimeOfDay to the real time of day.
  129.  */
  130.  
  131. static void UpdateUniversalTimeApprox _ARGS_((Timer_Ticks timeTicks, 
  132.                   ClientData  clientData));
  133. static Timer_QueueElement      updateElement;
  134.  
  135.  
  136.  
  137. /*
  138.  *----------------------------------------------------------------------
  139.  *
  140.  * TimerClock_Init --
  141.  *
  142.  *    Initializes the data structures necessary to manage the timer
  143.  *    modules' time of day clock.
  144.  *
  145.  * Results:
  146.  *     None.
  147.  *
  148.  * Side effects:
  149.  *     The system counter is initialized and started.
  150.  *
  151.  *----------------------------------------------------------------------
  152.  */
  153.  
  154. void
  155. TimerClock_Init()
  156. {
  157.  
  158.     Time    universal;
  159.     int        offset;
  160.     Boolean    DST;
  161.  
  162.     Sync_SemInitDynamic(&timer_ClockMutex,"Timer:timer_ClockMutex");
  163.  
  164.     Timer_CounterInit();
  165.     universal.seconds = 0;
  166.     universal.microseconds = 0;
  167.     offset = 0;
  168.     DST = TRUE;
  169.     TimerHardwareUniversalTimeInit(&universal, &offset, &DST);
  170.     TimerSetSoftwareUniversalTime(&universal, offset, DST);
  171.     /*
  172.      * Add the routine to fix the time of day to the timer queue.
  173.      * The routine is called every 10 seconds.
  174.      */
  175.  
  176.     updateElement.routine = UpdateUniversalTimeApprox;
  177.     updateElement.interval = 10 * timer_IntOneSecond;
  178.     Timer_ScheduleRoutine(&updateElement, TRUE);
  179. }
  180.  
  181.  
  182.  
  183. /*
  184.  *----------------------------------------------------------------------
  185.  *
  186.  *  Timer_GetRealTimeOfDay --
  187.  *
  188.  *    Retrieves an accurate value for the time of day. 
  189.  *    This routine is much slower than Timer_GetTimeOfDay but
  190.  *    returns a much more truthful value for the time of day.
  191.  *
  192.  *  Results:
  193.  *    The time of day is returned.
  194.  *
  195.  *  Side Effects:
  196.  *    Updates the global variables that stores the system up-time.
  197.  *
  198.  *----------------------------------------------------------------------
  199.  */
  200.  
  201. void
  202. Timer_GetRealTimeOfDay(timePtr, timerLocalOffsetPtr, DSTPtr)
  203.     Time *timePtr;        /* Buffer to hold TOD. */
  204.     int  *timerLocalOffsetPtr;    /* Optional buffer to hold local offset. */
  205.     Boolean *DSTPtr;        /* Optional buffer to hold DST allowed flag. */
  206. {
  207.     Timer_Ticks    curSystemTk;    /* current system time */
  208.     Timer_Ticks    diffTk;
  209.  
  210.     /*
  211.      *  Get the current system time and subtract from it the system time
  212.      *  when the universal time was last set. Add this difference to the value
  213.      *  of the stored universal time to get the current universal time.
  214.      */
  215.  
  216.     MASTER_LOCK(&timer_ClockMutex);
  217.  
  218.     Timer_GetCurrentTicks(&curSystemTk);
  219.  
  220.     Timer_SubtractTicks(curSystemTk, systemWhenUniversalSetTk, &diffTk);
  221.     Timer_AddTicks(diffTk, universalWhenSetTk, &diffTk);
  222.     Timer_TicksToTime(diffTk, timePtr);
  223.  
  224.     if (timerLocalOffsetPtr != (int *) NIL) {
  225.     *timerLocalOffsetPtr = timerUniversalToLocalOffset;
  226.     }
  227.     if (DSTPtr != (Boolean *) NIL) {
  228.     *DSTPtr = timerDSTAllowed;
  229.     }
  230.     MASTER_UNLOCK(&timer_ClockMutex);
  231.  
  232. }
  233.  
  234.  
  235. /*
  236.  *----------------------------------------------------------------------
  237.  *
  238.  *  Timer_GetRealTimeFromTicks --
  239.  *
  240.  *    Gives an accurate translation of ticks to time.  This routine
  241.  *    returns an absolute time value, rather than the relative time
  242.  *    value since booting returned by Timer_TicksToTime.  This routine
  243.  *    is slower, though.
  244.  *
  245.  *  Results:
  246.  *    The time of the tick value is returned.
  247.  *
  248.  *  Side Effects:
  249.  *    Updates the global variables that stores the system up-time.
  250.  *
  251.  *----------------------------------------------------------------------
  252.  */
  253.  
  254. void
  255. Timer_GetRealTimeFromTicks(ticks, timePtr, timerLocalOffsetPtr, DSTPtr)
  256.     Timer_Ticks    ticks;        /* Ticks value to convert to time. */
  257.     Time *timePtr;        /* Buffer to hold time value. */
  258.     int  *timerLocalOffsetPtr;    /* Optional buffer to hold local offset. */
  259.     Boolean *DSTPtr;        /* Optional buffer to hold DST allowed flag. */
  260. {
  261.     Timer_Ticks    diffTk;
  262.  
  263.     /*
  264.      * No masterlock, since we can be called from a call-back and get deadlock.
  265.      */
  266.  
  267.     /*
  268.      *  Get the tick value and subtract from it the system time
  269.      *  when the universal time was last set. Add this difference to the value
  270.      *  of the stored universal time to get the universal time at that tick
  271.      *  value.
  272.      */
  273.  
  274.     Timer_SubtractTicks(ticks, systemWhenUniversalSetTk, &diffTk);
  275.     Timer_AddTicks(diffTk, universalWhenSetTk, &diffTk);
  276.     Timer_TicksToTime(diffTk, timePtr);
  277.  
  278.     if (timerLocalOffsetPtr != (int *) NIL) {
  279.     *timerLocalOffsetPtr = timerUniversalToLocalOffset;
  280.     }
  281.     if (DSTPtr != (Boolean *) NIL) {
  282.     *DSTPtr = timerDSTAllowed;
  283.     }
  284.  
  285.     return;
  286. }
  287.  
  288.  
  289. /*
  290.  *----------------------------------------------------------------------
  291.  *
  292.  *  Timer_GetTimeOfDay--
  293.  *
  294.  *    Retrieves an approximate universal time. 
  295.  *    The value is approximate because it is updated at every
  296.  *    timer interrupt and timer interrupts may be delayed or dropped.
  297.  *    For an accurate value, use Timer_GetRealTimeOfDay.
  298.  *
  299.  *    Though the time of day value may not be accurate, it is
  300.  *    guaranteed to be monotonically increasing (i.e. it never goes
  301.  *    backwards) between calls to Timer_SetTimeOfDay.
  302.  *
  303.  *  Results:
  304.  *    The approximate time of day is returned.
  305.  *
  306.  *  Side Effects:
  307.  *    None.
  308.  *
  309.  *----------------------------------------------------------------------
  310.  */
  311.  
  312. void
  313. Timer_GetTimeOfDay(timePtr, timerLocalOffsetPtr, DSTPtr)
  314.     Time *timePtr;        /* Buffer to hold TOD. */
  315.     int  *timerLocalOffsetPtr;    /* Optional buffer to hold local offset. */
  316.     Boolean *DSTPtr;        /* Optional buffer to hold DST allowed flag. */
  317. {
  318.  
  319.  
  320.     MASTER_LOCK(&timer_ClockMutex);
  321.  
  322.     *timePtr = timer_UniversalApprox;
  323.  
  324.     if (timerLocalOffsetPtr != (int *) NIL) {
  325.     *timerLocalOffsetPtr = timerUniversalToLocalOffset;
  326.     }
  327.     if (DSTPtr != (Boolean *) NIL) {
  328.     *DSTPtr = timerDSTAllowed;
  329.     }
  330.  
  331.  
  332.     MASTER_UNLOCK(&timer_ClockMutex);
  333.  
  334. }
  335.  
  336.  
  337. /*
  338.  *----------------------------------------------------------------------
  339.  *
  340.  *  Timer_SetTimeOfDay --
  341.  *
  342.  *    Changes the universal time to a new value. This is done in
  343.  *    both the software and hardware clocks (if the machine has one).
  344.  *    IMPORTANT: we don't set the hardware clock because it will won't
  345.  *    work on a ds3100. See the comment in TimerSetHardwareUniversalTime.
  346.  *
  347.  *  Results:
  348.  *    None.
  349.  *
  350.  *  Side Effects:
  351.  *    Universal time is changed.
  352.  *
  353.  *----------------------------------------------------------------------
  354.  */
  355.  
  356. void
  357. Timer_SetTimeOfDay(newUniversal, newLocalOffset, newDSTAllowed)
  358.     Time newUniversal;        /* New value for time of day. */
  359.     int  newLocalOffset;    /* New value for local offset. */
  360.     Boolean newDSTAllowed;    /* New value for DST allowed flag. */
  361. {
  362.     MASTER_LOCK(&timer_ClockMutex);
  363.     TimerSetSoftwareUniversalTime(&newUniversal, 
  364.     newLocalOffset, newDSTAllowed);
  365. #ifdef NOTDEF
  366.     TimerSetHardwareUniversalTime(&newUniversal, newLocalOffset, 
  367.     newDSTAllowed);
  368. #endif
  369.     MASTER_UNLOCK(&timer_ClockMutex);
  370. }
  371.  
  372.  
  373. /*
  374.  *----------------------------------------------------------------------
  375.  *
  376.  *  TimerSetSoftwareUniversalTime --
  377.  *
  378.  *    Changes the universal time to a new value.
  379.  *
  380.  *  Results:
  381.  *    None.
  382.  *
  383.  *  Side Effects:
  384.  *    Updates the global variables that stores the universal time and the 
  385.  *    system time when it was set.
  386.  *
  387.  *----------------------------------------------------------------------
  388.  */
  389.  
  390. void
  391. TimerSetSoftwareUniversalTime(newUniversal, newLocalOffset, newDSTAllowed)
  392.     Time *newUniversal;        /* New value for time of day. */
  393.     int  newLocalOffset;    /* New value for local offset. */
  394.     Boolean newDSTAllowed;    /* New value for DST allowed flag. */
  395. {
  396.  
  397.     /*
  398.      *  Record when the universal time was changed by saving the current 
  399.      *  system time.
  400.      *  Also store the new universal time (it has to be converted to ticks),
  401.      *  the new local offset and the DST flag.
  402.      */
  403.  
  404.  
  405.  
  406.     timer_UniversalApprox = *newUniversal;
  407.  
  408.     Timer_GetCurrentTicks(&systemWhenUniversalSetTk);
  409.     Timer_TimeToTicks(*newUniversal, &universalWhenSetTk);
  410.  
  411.  
  412.     timerUniversalToLocalOffset = newLocalOffset;
  413.     timerDSTAllowed = newDSTAllowed;
  414.  
  415.  
  416. }
  417.  
  418. /*
  419.  *----------------------------------------------------------------------
  420.  *
  421.  * UpdateUniversalTimeApprox --
  422.  *
  423.  *    Called from the timer queue to make timer_UniversalApprox close
  424.  *    to the real current time..
  425.  *
  426.  * Results:
  427.  *    None.
  428.  *
  429.  * Side effects:
  430.  *    timerUTApprox is updated.
  431.  *
  432.  *----------------------------------------------------------------------
  433.  */
  434.  
  435. static void
  436. UpdateUniversalTimeApprox(timeTicks, clientData)
  437.     Timer_Ticks timeTicks;    /* Not used. */
  438.     ClientData    clientData;    /* Not used. */
  439. {
  440.     /* 
  441.      * No need to get the timerClock Mutex lock because 
  442.      * Timer_GetRealTimeOfDay gets it for us.
  443.      */
  444.     Timer_GetRealTimeOfDay(&timer_UniversalApprox, (int *) NIL, (int *) NIL);
  445.     Timer_ScheduleRoutine(&updateElement, TRUE);
  446. }
  447.  
  448.  
  449.